/**
 * @file CECContext.cpp Implementácia triedy CECContext.
 *
 * @author Martin Kosorinský.
 * @date 1.4.2009.
 */

#include "CECContext.hpp"

bool CECContext::initialized = false;
big CECContext::ecA = NULL;
big CECContext::ecB = NULL;
big CECContext::ecP = NULL;
big CECContext::ord = NULL;
big CECContext::bigBuffer[BIG_BUFFER_SIZE];
epoint * CECContext::G = NULL;
epoint * CECContext::H = NULL;


int CECContext::loadEcsFile(std::istream &ecSource, big a, big b, big p, big o, big x, big y) {
    int bits;
    miracl *mip = get_mip();

    mip->IOBASE = 10;
    ecSource >> bits;
    mip->IOBASE = 16;
    ecSource >> p >> a >> b >> ord >> x >> y;
    mip->IOBASE = 10;

    return bits;
}

void CECContext::init(std::istream &ecSource, int mrPointRep, int mrPrecision) {

    if (initialized) {
        cerr << "Error: '" << __FUNCTION__ << "': Kontext je uz inicializovany!" << endl;
        return;
    }

    mirsys(mrPrecision, 0);

    // inicializacia random generatoru .. ak pouzivame PVM kniznicu, generujeme v zavislosti od TID uzla
    irand((unsigned int)time(0));

    ecA = mirvar(0);
    ecB = mirvar(0);
    ecP = mirvar(0);
    ord = mirvar(0);
    G = epoint_init();
    H = epoint_init();

    if (ecSource.fail()) {
        cerr << "Error: '" << __FUNCTION__ << "': Zlyhalo nacitanie krivky zo suboru!" << endl;
        exit(1);
    }
    else {
        big x = mirvar(0);
        big y = mirvar(0);
        loadEcsFile(ecSource, ecA, ecB, ecP, ord, x , y);

        for (int i = 0; i < BIG_BUFFER_SIZE; i++) {
            bigBuffer[i] = mirvar(0);
        }

        ecurve_init(ecA, ecB, ecP, mrPointRep);
        if (!epoint_set(x, y, 0, G)) {
            cerr << "Error: '" << __FUNCTION__ << "': Bod (generator) nelezi na krivke!" << endl;
            exit(1);
        }
        initialized = true;

        setPoint(); // nastavenie hladaneho bodu na nahodny v grupe

        mirkill(x);
        mirkill(y);
    }
}

void CECContext::init(big a, big b, big p, big o, big x, big y, int mrPointRep) {

    if (initialized) {
        cerr << "Error: '" << __FUNCTION__ << "': Kontext je uz inicializovany!" << endl;
        return;
    }

    // inicializacia random generatoru .. ak pouzivame PVM kniznicu, generujeme v zavislosti od TID uzla
    irand((unsigned int)time(0));

    ecA = mirvar(0);
    ecB = mirvar(0);
    ecP = mirvar(0);
    ord = mirvar(0);
    G = epoint_init();
    H = epoint_init();

    copy(a, ecA);
    copy(b, ecB);
    copy(p, ecP);
    copy(o, ord);

    for (int i = 0; i < BIG_BUFFER_SIZE; i++) {
        bigBuffer[i] = mirvar(0);
    }

    ecurve_init(ecA, ecB, ecP, mrPointRep);
    if (!epoint_set(x, y, 0, G)) {
        cerr << "Error: '" << __FUNCTION__ << "': Bod (generator) nelezi na krivke!" << endl;
        exit(1);
    }
    initialized = true;

    setPoint(); // nastavenie hladaneho bodu na nahodny v grupe
}

void CECContext::init(std::istream &ecSource, std::istream &dlSource, int mrPointRep, int mrPrecision) {
    CECContext::init(ecSource, mrPointRep, mrPrecision);
    big x = mirvar(0);
    big y = mirvar(0);
    miracl *mip = get_mip();
    mip->IOBASE = 16;
    dlSource >> x;
    dlSource >> y;
    mip->IOBASE = 10;
    if (!epoint_set(x, y, 0, H)) {
        cerr << "Error: '" << __FUNCTION__ << "': Bod (zadanie DL) nelezi na krivke!" << endl;
        mirkill(x);
        mirkill(y);
        exit(1);
    }
    mirkill(x);
    mirkill(y);
}

void CECContext::getParams(big a, big b, big p, big o, epoint * g) {

    if (!initialized) {
        cerr << "Error: '" << __FUNCTION__ << "': Parametre krivky este neboli inicializovane!" << endl;
        return;
    }

    epoint_copy(CECContext::G, g);
    copy(ecA, a);
    copy(ecB, b);
    copy(ecP, p);
    copy(CECContext::ord, o);
}

void CECContext::free() {
    if (ecA != NULL)
        mirkill(ecA);
    if (ecB != NULL)
        mirkill(ecB);
    if (ecP != NULL)
        mirkill(ecP);
    if (ord != NULL)
        mirkill(ord);
    if (G != NULL)
        epoint_free(G);
    if (H != NULL)
        epoint_free(H);
    if (initialized) {
        for (int i = 0; i < BIG_BUFFER_SIZE; i++) {
            mirkill(bigBuffer[i]);
        }
    }
    mirexit();
    initialized = false;
}

void CECContext::setPoint(const big x, const big y) {
    if (!initialized) {
        cerr << "Error: '" << __FUNCTION__ << "': Najprv treba inicializovat kontext!" << endl;
        exit(1);
    }
    if (!epoint_set(x, y, 0, H)) {
        cerr << "Error: '" << __FUNCTION__ << "': Bod nelezi na krivke!" << endl;
        exit(1);
    }
}

void CECContext::setPoint(const epoint * P) {
    if (!initialized) {
        cerr << "Error: '" << __FUNCTION__ << "': Najprv treba inicializovat kontext!" << endl;
        exit(1);
    }
    if (P != NULL)
        epoint_copy((epoint*)P, H);
    else {
        bigrand(ord, bigBuffer[0]);
        ecurve_mult(bigBuffer[0], G, H);
    }
}

void CECContext::setPoint(const big n) {
    if (!initialized) {
        cerr << "Error: '" << __FUNCTION__ << "': Najprv treba inicializovat kontext!" << endl;
        exit(1);
    }
    else {
        ecurve_mult(n, G, H);
    }
}

void CECContext::getPoint(epoint * P) {
    if (!initialized) {
        cerr << "Error: '" << __FUNCTION__ << "': Najprv treba inicializovat kontext!" << endl;
        exit(1);
    }
    epoint_copy(H, P);
}

void CECContext::getGenerator(epoint * P) {
    if (!initialized) {
        cerr << "Error: '" << __FUNCTION__ << "': Najprv treba inicializovat kontext!" << endl;
        exit(1);
    }
    epoint_copy(G, P);
}
